﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using FDFtpSync.Core;
using FDFtpSync.Entities;
using FDFtpSync.Entities.Extensions;
using FDFtpSync.Utils;

namespace FDFtpSync.Client
{
    /*
     * CreatedOn: 2018-05-23
     * CreatedBy: Jackie Lee(天宇遊龍)
     */
    /// <summary>
    /// Ftp下载器
    /// </summary>
    public class FtpFileSyncServer : BaseSyncServer, IFileSyncServer
    {
        protected override void Run()
        {
            var clientConfig = SyncContext.Current.GetSyncConfig<ClientSyncConfig>();
            _lastRunTime = DateTime.Now;
            _isRunning = true;
            TryDo(() =>
            {
                Info("开始进入同步...");
                var client = new HttpClient();
                foreach (var clientPath in clientConfig.ClientPaths)
                {
                    var content = new StringContent(new { Password = clientConfig.ServerConnectPassword, PathName = clientPath.ServerName, clientConfig.SyncOwnedModelOnly }.ToJson());
                    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    var res = client.PostAsync(clientConfig.FileListUrl, content).Result.Content.ReadAsStringAsync().Result;
                    var apiRes = res.FromJson<ApiResult<List<TransFile>>>();
                    if (apiRes.Code == 0)
                    {
                        var tasks = new List<Task>();
                        foreach (var transFile in apiRes.Result)
                        {
                            var saveFileName = $"{clientPath.Path}{transFile.Path}";
                            if (transFile.Type == PathType.Dir)
                            {
                                PathHelper.CheckDir(saveFileName);
                            }
                            else
                            {
                                PathHelper.CheckDir(Path.GetDirectoryName(saveFileName));
                                if (!PathHelper.HasChanged(transFile, saveFileName))
                                {
                                    continue;
                                }
                                //bool bSuccess;
                                //do
                                //{
                                //    bSuccess = ThreadPool.QueueUserWorkItem(Download,
                                //        new { transFile, clientPath.ServerName, saveFileName });
                                //    if (!bSuccess)
                                //    {
                                //        Thread.Sleep(500);
                                //    }
                                //} while (!bSuccess);
                                //Download(new { transFile, clientPath.ServerName, saveFileName });
                                while (true)
                                {
                                    if (tasks.Count >= clientConfig.Threads)
                                    {
                                        if (Task.WhenAny(tasks).IsCompleted)
                                        {
                                            int count = 0;
                                            for (var i = 0; i < tasks.Count; ++i)
                                            {
                                                if (tasks[i].IsCompleted || tasks[i].IsCanceled)
                                                {
                                                    tasks.RemoveAt(i);
                                                    count++;
                                                }
                                            }

                                            if (count > 0)
                                                break;
                                        }
                                        Thread.Sleep(500);
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                tasks.Add(Task.Factory.StartNew(Download, new { transFile, clientPath.ServerName, saveFileName }));
                            }
                        }

                        if (clientConfig.SyncServerOnly)
                        {
                            PathHelper.CheckSyncFile(apiRes.Result, $"{clientPath.Path}");
                        }
                        Info($"{clientPath.ServerName}到{clientPath.Path}的{apiRes.Result.Count}个文件处理完成");
                    }
                    else
                    {
                        Info($"请求{clientPath.ServerName}失败：{apiRes.Message}");
                    }
                }
                Info("本次同步操作完成");
            });
            _isRunning = false;
        }

        private void Download(dynamic parameter)
        {
            TransFile serverFile = parameter.transFile;
            string saveFileName = parameter.saveFileName;
            string serverName = parameter.ServerName;

            TryDo(() => Download(serverFile, saveFileName, serverName));
        }

        //private void Download(TransFile serverFile, string saveFileName, string serverName)
        //{
        //    var clientConfig = SyncContext.Current.ClientSyncConfig;
        //    var path = PathHelper.FormatPath(serverFile.Path);
        //    var fileName = $"{clientConfig.FtpDownloadUrl.TrimEnd('/')}{path}";
        //    FtpWebRequest ftpReq = (FtpWebRequest)WebRequest.Create(fileName);
        //    ftpReq.Credentials = new NetworkCredential(clientConfig.FtpUser, clientConfig.FtpPassword);
        //    ftpReq.Method = WebRequestMethods.Ftp.DownloadFile;
        //    ftpReq.KeepAlive = false;
        //    ftpReq.UseBinary = false;
        //    ftpReq.UsePassive = true;

        //    FtpWebResponse ftpRes = (FtpWebResponse)ftpReq.GetResponse();
        //    var streamResp = ftpRes.GetResponseStream();
        //    if (ftpRes.StatusCode == FtpStatusCode.DataAlreadyOpen)
        //    {
        //        MemoryStream stream = new MemoryStream();
        //        streamResp.CopyTo(stream);
        //        var serverMd5 = GetFileMd5(serverFile.Path, serverName);//MD5Helper.Md5Stream(stream);
        //        stream.Seek(0, SeekOrigin.Begin);
        //        string localMd5;
        //        bool bNewFile = true;
        //        if (File.Exists(saveFileName))
        //        {
        //            localMd5 = MD5Helper.Md5File(saveFileName);
        //            if (serverMd5 == localMd5)
        //            {
        //                bNewFile = false;
        //                PathHelper.ChangeFileInfo(saveFileName, serverFile.CreatedTime, serverFile.ModifiedTime, serverFile.AccessedTime);
        //            }
        //            else
        //            {
        //                if (PathHelper.GetFileLength(saveFileName) > stream.Length)
        //                {
        //                    File.Delete(saveFileName);
        //                    WriteToFile(saveFileName, stream);
        //                }
        //                else
        //                {
        //                    WriteToFile(saveFileName, stream, true);
        //                }
        //            }
        //        }
        //        else
        //        {
        //            WriteToFile(saveFileName, stream);
        //        }
        //        if (bNewFile && serverMd5 == (localMd5 = MD5Helper.Md5File(saveFileName)))
        //        {
        //            PathHelper.ChangeFileInfo(saveFileName, serverFile.CreatedTime, serverFile.ModifiedTime, serverFile.AccessedTime);
        //            Info($"新下载的文件：{saveFileName}，{serverMd5},{localMd5}"); ;
        //        }
        //    }
        //    else
        //    {
        //        var sr = new StreamReader(streamResp);
        //        Info($"下载{serverFile.Path},{fileName}失败{sr.ReadToEnd()}");
        //    }
        //}

        private static object sync = new object();

        public FtpFileSyncServer(ILogger logger) : base(logger)
        {
        }

        private void Download(TransFile serverFile, string saveFileName, string serverName)
        {
            lock (sync)
            {
                var clientConfig = SyncContext.Current.GetSyncConfig<ClientSyncConfig>();
                var path = PathHelper.FormatPath(serverFile.Path);
                var fileName = $"{clientConfig.FtpDownloadUrl.TrimEnd('/')}{serverFile.RelativeRoot}{path}";
                FtpWebRequest ftpReq = (FtpWebRequest)WebRequest.Create(fileName);
                ftpReq.Credentials = new NetworkCredential(clientConfig.FtpUser, clientConfig.FtpPassword);
                ftpReq.Method = WebRequestMethods.Ftp.DownloadFile;
                ftpReq.KeepAlive = false;
                ftpReq.UseBinary = false;
                ftpReq.UsePassive = false;

                var serverMd5 = GetFileMd5(serverFile.Path, serverName);
                string localMd5;
                var bAppend = false;
                if (File.Exists(saveFileName))
                {
                    localMd5 = MD5Helper.Md5File(saveFileName);
                    if (serverMd5 == localMd5)
                    {
                        PathHelper.ChangeFileInfo(serverFile.Type, saveFileName, serverFile.CreatedTime, serverFile.ModifiedTime,
                            serverFile.AccessedTime);
                        return;
                    }
                    if (PathHelper.GetFileLength(saveFileName) > serverFile.Size)
                    {
                        File.Delete(saveFileName);
                        //WriteToFile(saveFileName, stream);
                    }
                    else
                    {
                        //WriteToFile(saveFileName, stream, true);
                        bAppend = true;
                    }
                }
                using (FtpWebResponse ftpRes = (FtpWebResponse)ftpReq.GetResponse())
                {
                    var stream = ftpRes.GetResponseStream();
                    using (var fs = new FileStream(saveFileName, FileMode.Append, FileAccess.Write))
                    {
                        if (bAppend)
                        {
                            fs.Seek(fs.Length, SeekOrigin.Begin);
                        }

                        var buffer = new byte[1024 * 1024 * 1024];
                        int count;
                        while ((count = stream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            fs.Write(buffer, 0, count);
                        }
                    }
                }

                if (serverMd5 == (localMd5 = MD5Helper.Md5File(saveFileName)))
                {
                    PathHelper.ChangeFileInfo(serverFile.Type, saveFileName, serverFile.CreatedTime, serverFile.ModifiedTime,
                        serverFile.AccessedTime);
                    Info($"新下载的文件：{saveFileName}，{serverMd5},{localMd5}");
                    ;
                }
            }
        }

        //private void Download(dynamic parameter)
        //{
        //    TransFile serverFile = parameter.transFile;
        //    string pathName = parameter.ServerName;
        //    string saveFileName = parameter.saveFileName;

        //    using (var client = new HttpClient())
        //    {
        //        var content = new StringContent(new { FileName = serverFile.Path, PathName = pathName }.ToJson());
        //        content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
        //        var resp = client.PostAsync(SyncContext.Current.ClientSyncConfig.DownloadUrl, content).Result;
        //        if (resp.StatusCode == HttpStatusCode.OK)
        //        {
        //            var stream = resp.Content.ReadAsStreamAsync().Result;
        //            var serverMd5 = MD5Helper.Md5Stream(stream);
        //            stream.Seek(0, SeekOrigin.Begin);
        //            string localMd5;
        //            bool bNewFile = true;
        //            if (File.Exists(saveFileName))
        //            {
        //                localMd5 = MD5Helper.Md5File(saveFileName);
        //                if (serverMd5 == localMd5)
        //                {
        //                    bNewFile = false;
        //                    PathHelper.ChangeFileInfo(saveFileName, serverFile.CreatedTime, serverFile.ModifiedTime, serverFile.AccessedTime);
        //                }
        //                else
        //                {
        //                    WriteToFile(saveFileName, stream, true);
        //                }
        //            }
        //            else
        //            {
        //                WriteToFile(saveFileName, stream);
        //            }
        //            if (bNewFile && serverMd5 == (localMd5 = MD5Helper.Md5File(saveFileName)))
        //            {
        //                PathHelper.ChangeFileInfo(saveFileName, serverFile.CreatedTime, serverFile.ModifiedTime, serverFile.AccessedTime);
        //                Info($"新下载的文件：{saveFileName}，{serverMd5},{localMd5}"); ;
        //            }
        //        }
        //        else
        //        {
        //            Info($"下载{serverFile.Path},{pathName}失败{resp.Content.ReadAsStringAsync().Result}");
        //        }
        //    }
        //}

    }
}